#include "Game.h"

bool	_onSound = true;
bool	_onMusic = true;

Game::Game(HINSTANCE hInstance, LPSTR name, int screenwidth, int screenheight, int isfullscreen, int framerate)
{
	_pd3d = NULL;
	_pd3ddv = NULL;
	_back_buffer = NULL;

	_name = name;
	_is_full_screen = isfullscreen;
	_frame_rate = framerate;

	_screen_width = screenwidth;
	_screen_height = screenheight;

	_input = NULL;

	_state = NULL;
}

Game::~Game()
{
	delete _input;
	delete _resources;
	
	delete _state;
}

bool Game::_InitWindow()
{
	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);

	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.hInstance = _hInstance;

	wc.lpfnWndProc = (WNDPROC)Game::_WinProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _name;
	wc.hIconSm = NULL;

	RegisterClassEx(&wc);

	DWORD style;
	if (_is_full_screen)
		style = WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP;
	else
		style = WS_OVERLAPPED;// WS_OVERLAPPEDWINDOW;

	_hWnd =
		CreateWindow(
		_name,
		_name,
		style,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		_screen_width,
		_screen_height,
		NULL,
		NULL,
		_hInstance,
		NULL);

	if (!_hWnd)
	{
		return false;
	}

	ShowWindow(_hWnd, SW_SHOWNORMAL);
	UpdateWindow(_hWnd);

	return true;
}

bool Game::_InitDirectX()
{
	_pd3d = Direct3DCreate9(D3D_SDK_VERSION);
	D3DPRESENT_PARAMETERS d3dpp;

	ZeroMemory(&d3dpp, sizeof(d3dpp));

	d3dpp.Windowed = _is_full_screen ? FALSE : TRUE;

	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferHeight = _screen_height;
	d3dpp.BackBufferWidth = _screen_width;

	_pd3d->CreateDevice(
		D3DADAPTER_DEFAULT,
		D3DDEVTYPE_HAL,
		_hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&d3dpp,
		&_pd3ddv);

	if (_pd3ddv == NULL)
	{
		return false;
	}

	_pd3ddv->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &_back_buffer);

	D3DXCreateSprite(_pd3ddv, &_sprite_handler);

	return true;
}

LRESULT CALLBACK Game::_WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}

	return 0;
}

bool Game::Init()
{
	if (!_InitWindow()) return false;
	if (!_InitDirectX()) return false;

	_input = new Input(_hWnd);
	if (!_input->InitDirectInput()) return false;

	_LoadResources();

	return true;
}

void Game::Run()
{
	MSG msg;
	int done = 0;
	DWORD frame_start = GetTickCount();;

	float tick_per_frame = 100.0f / _frame_rate;

	while (!done)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
			{
				if (_state)
					_state->Release();

				done = 1;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		_input->ProcessKeyboard();
		if (_state)
		{
			_state->ProcessInput(_input);
		}

		DWORD now = GetTickCount();
		_delta_time = now - frame_start;

		if (_delta_time >= tick_per_frame)
		{
			frame_start = now;
			_delta_time = tick_per_frame;
			_UpdateWorld(0.016f);
			_RenderFrame();
		}
	}
}

void Game::_LoadResources()
{
	_resources = Resources::CreateResources(_pd3ddv, _back_buffer, _hWnd);
	
	// Init something
	_state = new MenuState(_resources);

	_resources->_audio->LoopSound(_resources->Background);
}

void Game::_UpdateWorld(float delta)
{
	// Update State
	if (_state)
	{
		_state->Update(delta);

		if (_state->IsClose())
		{
			ChangeState();
		}
	}
}

void Game::_RenderFrame()
{
	_pd3ddv->BeginScene();
	// Clear back buffer with BLACK
	_pd3ddv->ColorFill(_back_buffer, NULL, D3DCOLOR_XRGB(255, 255, 255));

	//--------------------------------------------------------------
	// Draw game
	_sprite_handler->Begin(D3DXSPRITE_ALPHABLEND);
	if (_state)
	{
		_state->Render(_sprite_handler);
	}

	_sprite_handler->End();
	_pd3ddv->EndScene();

	_pd3ddv->Present(NULL, NULL, NULL, NULL);
}

void Game::ChangeState()
{
	GameState st = _state->NextState();

	_state->Release();
	delete _state;
	_state = NULL;

	switch (st)
	{
	case ST_Menu:
		_state = new MenuState(_resources);
		break;
	case ST_Play:
		_state = new PlayState(_resources, true);
		break;
	case ST_Continues:
		_state = new PlayState(_resources, false);
		break;
	case ST_Option:
		_state = new OptionState(_resources);
		break;
	case ST_About:
		_state = new AboutState(_resources);
		break;
	case ST_Exit:
		PostMessage(_hWnd, WM_DESTROY, 0, 0);
		break;
	default:
		break;
	}
}
